`ifndef _CASE1_SV
`define _CASE1_SV

class case1_sequence extends uvm_sequence #(transaction_dut);
    transaction_dut m_trans;
    rand int data_size = -1;
    rand int ntrans = 10;

    `uvm_object_utils(case1_sequence)
    function new(string name = "case1_sequence");
        super.new(name);
    endfunction

    constraint cstr{
        soft data_size inside {[4:3200]};
        soft ntrans inside {[5:100]};
    }

    virtual task body();
        `uvm_info("case1_sequence",  $sformatf("send %0d transaction to sequencer", ntrans), UVM_LOW)
        repeat(ntrans) begin	    
            `uvm_do_with(m_trans, { local::data_size > 0 -> pload.size() == local::data_size; } )
        end
        #1000;
    endtask
endclass

// -- virtual sequence for data
class case1_vseq extends uvm_sequence;
    `uvm_object_utils(case1_vseq)
    `uvm_declare_p_sequencer(virtual_sequencer)

    function new(string name = "case1_vseq");
        super.new(name);
    endfunction
    virtual task body();
        case1_sequence dut_seq;
        uvm_status_e status;
        uvm_reg_data_t value;

        if(starting_phase != null)
            starting_phase.raise_objection(this);
        
        #1000;
        
        `uvm_do_on_with(dut_seq, p_sequencer.p_dut_sqr, {ntrans == 5; data_size == -1; })

        #10000;

        p_sequencer.p_rm.counter.read(status, value);
        `uvm_info("case1_vseq", $sformatf("after data transfer, reg_model counter's value is %0d", value), UVM_LOW);
        
        if(starting_phase != null)
            starting_phase.drop_objection(this);
    endtask
    
    
endclass 

// -- virtual sequence for register model
class case1_cfg_vseq extends uvm_sequence;
    `uvm_object_utils(case1_cfg_vseq)
    `uvm_declare_p_sequencer(virtual_sequencer)

    function new(string name = "case1_cfg_vseq");
        super.new(name);
    endfunction
    virtual task body();
        uvm_status_e status;
        uvm_reg_data_t value;

        if(starting_phase != null)
            starting_phase.raise_objection(this);
        
        #1000;

        // set value of registers via uvm_reg::poke() for UVM_BACKDOOR
        p_sequencer.p_rm.invert.poke(status, {15'h00, 1'b0});
        p_sequencer.p_rm.counter.poke(status, {15'h00, 32'h2000f0});
        // read out the value form register
        p_sequencer.p_rm.invert.peek(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after poke, invert's value is %0h", value), UVM_LOW)
        p_sequencer.p_rm.counter.peek(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after poke, counter's value is %0h", value), UVM_LOW)

        // set value of registers via uvm_reg::write() for UVM_BACKDOOR
        p_sequencer.p_rm.invert.write(status, {15'h00, 1'b1}, UVM_BACKDOOR);
        p_sequencer.p_rm.counter.write(status, 32'h2000f0, UVM_BACKDOOR);
        // read out the value form register
        p_sequencer.p_rm.invert.read(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after UVM_BACKDOOR write, invert's value is %0h", value), UVM_LOW)
        p_sequencer.p_rm.counter.read(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after UVM_BACKDOOR write, counter's value is %0h", value), UVM_LOW)

        // set value of registers via uvm_reg::poke() for UVM_BACKDOOR
        p_sequencer.p_rm.invert.poke(status, {15'h00, 1'b0});
        p_sequencer.p_rm.counter.poke(status, {15'h00, 32'h2000f0});
        // read out the value form register
        p_sequencer.p_rm.invert.peek(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after poke, invert's value is %0h", value), UVM_LOW)
        p_sequencer.p_rm.counter.peek(status, value);
        `uvm_info("case1_cfg_vseq", $sformatf("after poke, counter's value is %0h", value), UVM_LOW)

        #5000;
        if(starting_phase != null)
            starting_phase.drop_objection(this);
    endtask

endclass 


class case1 extends base_test;
    `uvm_component_utils(case1)
    function new(string name = "case1", uvm_component parent = null);
        super.new(name, parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        /* 1. use default_sequence */
        uvm_config_db #(uvm_object_wrapper)::set(this, "v_sqr.configure_phase", "default_sequence", case1_cfg_vseq::type_id::get());
        uvm_config_db #(uvm_object_wrapper)::set(this, "v_sqr.main_phase", "default_sequence", case1_vseq::type_id::get());
    
    endfunction

endclass

`endif

